package main

import (
    "adkr/pkg/crypto"
    "encoding/json"
    "flag"
    "hash/crc32"
    "log"
    "os"
    "path/filepath"
    "fmt"
)

func main() {
    outDir := flag.String("out", "pycompat_comprehensive", "output directory for comprehensive samples")
    flag.Parse()
    
    if err := os.MkdirAll(*outDir, 0o755); err != nil {
        log.Fatalf("mkdir: %v", err)
    }
    
    s := crypto.NewSerializer()
    g1 := crypto.GetG1()
    g2 := crypto.GetG2()
    var zr1, zr2 crypto.ZR
    zr1.SetRandom()
    zr2.SetRandom()
    var gt1, gt2 crypto.GT
    gt1.SetRandom()
    gt2.SetRandom()
    
    // Create comprehensive test cases
    testCases := map[string]interface{}{
        // Basic types
        "basic_g1.bin": g1,
        "basic_g2.bin": g2,
        "basic_zr.bin": zr1,
        "basic_gt.bin": gt1,
        
        // Nested lists
        "nested_list.bin": []interface{}{
            []interface{}{g1, g2},
            []interface{}{zr1, zr2},
            []interface{}{gt1, gt2},
        },
        
        // Nested tuples
        "nested_tuple.bin": crypto.Tuple{
            Items: []interface{}{
                crypto.Tuple{Items: []interface{}{g1, zr1}},
                crypto.Tuple{Items: []interface{}{g2, zr2}},
            },
        },
        
        // Complex map with nested structures
        "complex_map.bin": map[string]interface{}{
            "level1": map[string]interface{}{
                "g1": g1,
                "list": []interface{}{zr1, zr2},
            },
            "level2": crypto.Tuple{
                Items: []interface{}{
                    gt1,
                    map[string]interface{}{
                        "nested": []interface{}{g2, gt2},
                    },
                },
            },
        },
        
        // Mixed types in list
        "mixed_list.bin": []interface{}{
            g1,
            zr1,
            []byte("hello world"),
            crypto.Tuple{Items: []interface{}{g2, zr2}},
            map[string]interface{}{
                "key1": gt1,
                "key2": []interface{}{g1, g2},
            },
        },
        
        // Empty structures
        "empty_list.bin": []interface{}{},
        "empty_tuple.bin": crypto.Tuple{Items: []interface{}{}},
        "empty_map.bin": map[string]interface{}{},
        
        // Single element structures
        "single_list.bin": []interface{}{g1},
        "single_tuple.bin": crypto.Tuple{Items: []interface{}{zr1}},
        "single_map.bin": map[string]interface{}{"key": gt1},
    }
    
    log.Printf("Generating comprehensive serialization samples...")
    
    // manifest entries
    type entry struct{ Name string `json:"name"`; Size int `json:"size"`; CRC32C string `json:"crc32c"` }
    var manifest []entry

    for name, obj := range testCases {
        // Serialize
        data, err := s.SerializePyCompat(obj)
        if err != nil {
            log.Fatalf("Failed to serialize %s: %v", name, err)
        }
        
        // Write to file
        filepath := filepath.Join(*outDir, name)
        if err := os.WriteFile(filepath, data, 0o644); err != nil {
            log.Fatalf("Failed to write %s: %v", name, err)
        }
        // write .crc alongside (CRC32C Castagnoli)
        crc := crc32.Checksum(data, crc32.MakeTable(crc32.Castagnoli))
        if err := os.WriteFile(filepath+".crc", []byte(
            func(v uint32) string { return fmt.Sprintf("%08x\n", v) }(crc),
        ), 0o644); err != nil {
            log.Fatalf("Failed to write crc for %s: %v", name, err)
        }
        
        // Verify round-trip
        obj2, err := s.DeserializePyCompat(data)
        if err != nil {
            log.Fatalf("Failed to deserialize %s: %v", name, err)
        }
        
        data2, err := s.SerializePyCompat(obj2)
        if err != nil {
            log.Fatalf("Failed to re-serialize %s: %v", name, err)
        }
        
        if len(data) != len(data2) {
            log.Printf("Warning: %s round-trip size mismatch: %d -> %d", name, len(data), len(data2))
        } else {
            identical := true
            for i := 0; i < len(data); i++ {
                if data[i] != data2[i] {
                    identical = false
                    break
                }
            }
            if identical {
                log.Printf("✓ %s: %d bytes, round-trip identical", name, len(data))
            } else {
                log.Printf("Warning: %s round-trip content differs", name)
            }
        }
        // append to manifest
        manifest = append(manifest, entry{Name: name, Size: len(data), CRC32C: func(v uint32) string { return fmt.Sprintf("%08x", v) }(crc)})
    }
    
    // write manifest.json
    mf := filepath.Join(*outDir, "manifest.json")
    b, _ := json.MarshalIndent(manifest, "", "  ")
    _ = os.WriteFile(mf, b, 0o644)

    log.Printf("Comprehensive samples written to %s", *outDir)
}
